/**
 @file dal_user_sim_mchip.c

 @date 2020-01-19

 @version v1.0

*/

#if (1 == SDK_WORK_PLATFORM) && (!(defined(GREATBELT) || defined(GOLDENGATE)))
#ifdef CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-inline"
#pragma clang diagnostic ignored "-Wgnu-designator"
#endif

#include "sal.h"
#include "dal.h"
#include "dal_user_sim_mchip.h"
#include "../../../../libctccli/include/ctc_cli.h"

/*must 16 bytes*/
#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT)
typedef struct dal_shm_dma_mem_s
{
    uint32  size;
    uint32  free  : 1;
    uint32  magic : 31;
    struct dal_shm_dma_mem_s* next;
}dal_shm_dma_mem_t;
#else
typedef struct dal_shm_dma_mem_s
{
    uint32  magic;
    uint32  size;
    uint32  free;
    struct dal_shm_dma_mem_s* next;
}dal_shm_dma_mem_t;
#endif


extern dal_dma_info_t dma_info[CTC_MAX_LOCAL_CHIP_NUM];
uint8 g_dal_work_mode = 0;
void* g_dal_shm_addr[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
void* g_dal_dma_ptr[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
uint32 g_dal_shmid[CTC_MAX_LOCAL_CHIP_NUM] = {0};
dal_shm_cmd_t* g_dal_shm_pci_addr[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
uint8 g_dal_sim_gchip[CTC_MAX_LOCAL_CHIP_NUM] = {0};
dal_shm_dma_mem_t* g_dal_dma_shm_list[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
sal_mutex_t* dal_shm_dma_lock[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};
sal_mutex_t* dal_drv_shm_lock[CTC_MAX_LOCAL_CHIP_NUM] = {NULL};

/*
  0: working for sdk
  1: working for cmodel
*/
uint8
dal_sim_set_mchip_mode(uint8 mode)
{
    g_dal_work_mode = mode;
    return 0;
}
uint8
dal_sim_set_mchip_gchip(uint8 lchip, uint8 gchip)
{
    g_dal_sim_gchip[lchip] = gchip;
    return 0;
}
uint8
dal_sim_get_mchip_mode()
{
    return g_dal_work_mode;
}


uint8
dal_sdk_work_with_shm()
{
    return (!g_dal_work_mode && g_dal_shm_addr[0]) ? 1 : 0;
}

uint8*
dal_shm_get_cmodel_cli_cmd_ptr(uint8 lchip)
{
    return g_dal_shm_addr[lchip] ? ((uint8*)g_dal_shm_addr[lchip] + DAL_SHM_DMA_SIZE) : NULL;
}

#include <fcntl.h>
#include <poll.h>
#include "drv_api.h"


#define DRV_ENTRY_LOCK(lchip)         sal_mutex_lock(dal_drv_shm_lock[lchip])
#define DRV_ENTRY_UNLOCK(lchip)       sal_mutex_unlock(dal_drv_shm_lock[lchip])
extern int32 sys_usw_chip_check_active(uint8 lchip);

#if defined(TSINGMA_MX) || defined(TSINGMA_GX) || defined(ARCTIC)
extern  int32 cm_mem_model_pci_read(uint8, uint32, uint32*);
extern  int32 cm_mem_model_pci_write(uint8, uint32, uint32);
#endif

#include "usw/include/drv_chip_ctrl.h"
#include "usw/include/drv_common.h"

#if (SDK_WORK_PLATFORM == 1 && SDK_WORK_ENV == 1)  /*simulation */
uint32 cm_sim_intr_engine(void);
#endif




#define SHM_DMA_LOCK() sal_mutex_lock(dal_shm_dma_lock[lchip])
#define SHM_DMA_UNLOCK() sal_mutex_unlock(dal_shm_dma_lock[lchip])

#define DEFAULT_SHM_PATHNAME "_shm_tmp_d"
#define DEFAULT_SHM_FILENAME "./ctc_shm.cfg"
#define DEFAULT_SHM_PROJ_ID 1 /*1-255*/ /*lchip_id + 1*/
#include <sys/ipc.h>
#include <sys/shm.h>

int
dal_destroy_shm(int shmid)
{
    if(shmctl(shmid,IPC_RMID,NULL) < 0)
    {
        return -1;
    }
    return 0;
}
int
dal_create_shm(char* file, uint8 proj_id, uint32 size)
{
    int shmid = 0;
    key_t key = 0;

    if (!size)
    {
        return -1;
    }
    if (!proj_id)
    {
        proj_id = DEFAULT_SHM_PROJ_ID;
    }


    key = ftok(file, proj_id);
    if((shmid = shmget(key, size, IPC_CREAT| 0666)) < 0)
    {
        return -1;
    }
    return shmid;
}
void* dal_get_shm(int shmid)
{
    void* addr = shmat(shmid,NULL,0);
    if ((void*)-1 == addr)
    {
        return NULL;
    }
    return addr;
}

int32
dal_op_shm_init_gchip(uint8 lchip, uint8 gchip)
{
    sal_file_t local_fp = NULL;
    char* file = NULL;
    char buffer[512];

    local_fp = sal_fopen(DEFAULT_SHM_FILENAME, "r");
    if (NULL == local_fp)
    {
        return 0;
    }
    while (NULL != sal_fgets(buffer, 512, local_fp))
    {
        /*comment line*/
        if ('#' == buffer[0])
        {
            continue;
        }
        buffer[sal_strlen(buffer) - 1] = '\0';
        file = buffer;
        break;
    }
    sal_fclose(local_fp);

    if (!g_dal_shmid[lchip])
    {
        g_dal_shmid[lchip] = dal_create_shm(file, gchip + 1, DAL_SHM_DMA_SIZE + DAL_SHM_CLI_SIZE + DAL_SHM_PCI_SIZE);
        g_dal_shm_addr[lchip] = dal_get_shm(g_dal_shmid[lchip]);
        if (NULL == g_dal_shm_addr[lchip])
        {
            return -1;
        }
        g_dal_dma_ptr[lchip] = g_dal_shm_addr[lchip];
        g_dal_shm_pci_addr[lchip] = (dal_shm_cmd_t*)((uint8*)g_dal_shm_addr[lchip] + DAL_SHM_DMA_SIZE + DAL_SHM_CLI_SIZE);

        if (g_dal_work_mode) /*working in cmodel*/
        {
            sal_memset(g_dal_shm_pci_addr[lchip], 0, DAL_SHM_PCI_SIZE);
            g_dal_shm_pci_addr[lchip]->working = 1; /*means sim model working*/
        }
        if (!g_dal_shm_pci_addr[lchip]->working)
        {
            DAL_DEBUG_DUMP("sim model is not worked!\n");
            return -1;
        }

        if (!g_dal_work_mode) /*sdk pipeline*/
        {
            uint64 pbase = 0;
            ((uint32*)g_dal_dma_ptr[lchip])[0] = ((uintptr)g_dal_dma_ptr[lchip]) & 0xFFFFFFFF;
#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT)
            ((uint32*)g_dal_dma_ptr[lchip])[1] = ((uintptr)g_dal_dma_ptr[lchip]) >> 32;
#endif
            g_dal_dma_shm_list[lchip] = (dal_shm_dma_mem_t*)g_dal_dma_ptr[lchip] + 1;
            g_dal_dma_shm_list[lchip]->size = DAL_SHM_DMA_SIZE - sizeof(dal_shm_dma_mem_t) - sizeof(uintptr);
            g_dal_dma_shm_list[lchip]->free = 1;
            g_dal_dma_shm_list[lchip]->next = NULL;

            dma_info[lchip].size = DAL_SHM_DMA_SIZE;
            dma_info[lchip].virt_base = (unsigned int*)g_dal_dma_ptr[lchip];
            pbase = (uintptr)dma_info[lchip].virt_base;
            dma_info[lchip].phy_base = (uint32)pbase;
            pbase >>= 32;
            dma_info[lchip].phy_base_hi = pbase;
        }
    }

    if (!g_dal_work_mode && !dal_shm_dma_lock[lchip])
    {
        sal_mutex_create(&dal_shm_dma_lock[lchip]);
    }
    if (!g_dal_work_mode && !dal_drv_shm_lock[lchip])
    {
        sal_mutex_create(&dal_drv_shm_lock[lchip]);
    }

    return 0;
}

void
_dal_shm_parser_init_json_gchip(sal_file_t local_fp)
{
    uint32 val = 0;
    char* p_str;
    char buffer[128] = {0};
    while (NULL != sal_fgets(buffer, 128, local_fp))
    {
        /*comment line*/
        if ('#' == buffer[0])
        {
            continue;
        }
        buffer[sal_strlen(buffer) - 1] = '\0';
        if (NULL != (p_str = sal_strstr(buffer, "\"gchip\"")))
        {
            char str_gchip[CTC_MAX_LOCAL_CHIP_NUM][16] = {{0}};
            uint8 idx = 0;
            uint8 chip_idx = 0;
            uint8 flag = 0;
            do{
                if (*p_str == '[')
                {
                    flag = 1;
                    continue;
                }
                else if (*p_str == ']')
                {
                    flag = 0;
                    str_gchip[chip_idx][idx] = '\0';
                    chip_idx++;
                    idx = 0;
                    break;
                }else if (*p_str == ',')
                {
                    str_gchip[chip_idx][idx] = '\0';
                    chip_idx++;
                    idx = 0;
                    continue;
                }
                if (flag && (*p_str != ' '))
                {
                    str_gchip[chip_idx][idx++] = *p_str;
                }
            }while (*(++p_str) != '\0');
            idx = 0;
            do {
                    if (sal_strlen(str_gchip[idx]) > 2 && !sal_memcmp(str_gchip[idx], "0x", 2))
                    {
                        sal_sscanf(str_gchip[idx] + 2, "%x", &val);
                    }
                    else
                    {
                        sal_sscanf(str_gchip[idx], "%d", &val);
                    }
                    g_dal_sim_gchip[idx] = val;
               }while(++idx < chip_idx);
            break;
        }
    }
}
void
_dal_shm_parser_init_cfg_gchip(sal_file_t local_fp)
{
    uint32 val = 0;
    uint32 val1 = 0;
    char* p_str;
    char buffer[128] = {0};
    while (NULL != sal_fgets(buffer, 128, local_fp))
    {
        /*comment line*/
        if ('#' == buffer[0])
        {
            continue;
        }
        buffer[sal_strlen(buffer) - 1] = '\0';
        if ((NULL != (p_str = sal_strstr(buffer, "Local chip"))) && sal_strstr(buffer, "[") && sal_strstr(buffer, "]"))
        {
            sal_sscanf(p_str + sal_strlen("Local chip"), "%d", &val);
            sal_sscanf(sal_strstr(buffer, "=") + 1, "%d", &val1);
            g_dal_sim_gchip[val] = val1;
        }
    }
}

int32
dal_op_shm_init(uint8 lchip)
{
    sal_file_t local_fp = NULL;

    /* parser chip_config */
    if (0 == lchip && 0 == g_dal_work_mode)
    {
        if (NULL != (local_fp = sal_fopen("init_profile.json", "r")))
        {
            _dal_shm_parser_init_json_gchip(local_fp);
            sal_fclose(local_fp);
            goto shm_init;
        }
        else if (NULL != (local_fp = sal_fopen("chip_profile.cfg", "r")))
        {
            _dal_shm_parser_init_cfg_gchip(local_fp);
            sal_fclose(local_fp);
            goto shm_init;
        }
    }
shm_init:
    return dal_op_shm_init_gchip(lchip, g_dal_sim_gchip[lchip]);
}

int32
dal_op_shm_deinit(uint8 lchip)
{
    char cmd[80] = {0};

    if (!g_dal_work_mode && dal_shm_dma_lock[lchip])
    {
        sal_mutex_destroy(dal_shm_dma_lock[lchip]);
        dal_shm_dma_lock[lchip] = NULL;
    }
    if (!g_dal_work_mode && dal_drv_shm_lock[lchip])
    {
        sal_mutex_destroy(dal_drv_shm_lock[lchip]);
        dal_drv_shm_lock[lchip] = NULL;
    }

    if (g_dal_work_mode)
    {
        if (g_dal_shmid[lchip])
        {
            dal_destroy_shm(g_dal_shmid[lchip]);
            sal_snprintf(cmd, sizeof(cmd), "ipcrm -m %d", g_dal_shmid[lchip]);
            system(cmd);
            g_dal_shmid[lchip] = 0;
        }
    }
    return 0;
}


#define DRV_SHM_WAIT while (0 == shm_cmd->done){sal_udelay(1);};
#define DRV_SHM_WAIT_VAL
int32
drv_usw_chip_sram_tbl_read_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->io_type = DAL_SHM_IO_NORMAL;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->op = DRV_IOC_READ;
    shm_cmd->index = index;
    shm_cmd->tbl_type = DRV_TBL_TYPE_NORMAL;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    sal_memcpy(data, shm_cmd->data, shm_cmd->len);
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
drv_usw_chip_sram_tbl_write_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->io_type = DAL_SHM_IO_NORMAL;
    shm_cmd->op = DRV_IOC_WRITE;
    shm_cmd->index = index;
    shm_cmd->tbl_type = DRV_TBL_TYPE_NORMAL;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    sal_memcpy(shm_cmd->data, data, shm_cmd->len);
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
drv_usw_chip_dyn_tbl_read_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->io_type = DAL_SHM_IO_NORMAL;
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->op = DRV_IOC_READ;
    shm_cmd->index = index;
    shm_cmd->tbl_type = DRV_TBL_TYPE_DYN;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    sal_memcpy(data, shm_cmd->data, shm_cmd->len);
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
drv_usw_chip_dyn_tbl_write_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->io_type = DAL_SHM_IO_NORMAL;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->op = DRV_IOC_WRITE;
    shm_cmd->index = index;
    shm_cmd->tbl_type = DRV_TBL_TYPE_DYN;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    sal_memcpy(shm_cmd->data, data, shm_cmd->len);
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
drv_usw_chip_tcam_tbl_read_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->io_type = DAL_SHM_IO_TCAM;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->op = DRV_IOC_READ;
    shm_cmd->tbl_type = DRV_TBL_TYPE_TCAM;
    shm_cmd->index = index;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    sal_memcpy((uint8*)(((tbl_entry_t *)data)->data_entry), (uint8*)((uint8*)shm_cmd->data + sizeof(tbl_entry_t)), shm_cmd->len);
    sal_memcpy((uint8*)(((tbl_entry_t *)data)->mask_entry), (uint8*)((uint8*)shm_cmd->data + sizeof(tbl_entry_t) + shm_cmd->len), shm_cmd->len);
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
drv_usw_chip_tcam_tbl_write_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->io_type = DAL_SHM_IO_TCAM;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->op = DRV_IOC_WRITE;
    shm_cmd->tbl_type = DRV_TBL_TYPE_TCAM;
    shm_cmd->index = index;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    sal_memcpy((uint8*)((uint8*)shm_cmd->data + sizeof(tbl_entry_t)), ((tbl_entry_t *)data)->data_entry, shm_cmd->len);
    sal_memcpy((uint8*)((uint8*)shm_cmd->data + sizeof(tbl_entry_t) + shm_cmd->len), ((tbl_entry_t *)data)->mask_entry, shm_cmd->len);
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
drv_usw_chip_tcam_tbl_remove_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* data)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->io_type = DAL_SHM_IO_TCAM;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->op = DRV_IOC_REMOVE;
    shm_cmd->tbl_type = DRV_TBL_TYPE_TCAM;
    shm_cmd->index = index;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}
int32
dal_ioctl_oam_api_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->op = (DRV_IOC_OP(cmd) == DRV_IOC_WRITE) ? DRV_IOC_WRITE : DRV_IOC_READ;
    shm_cmd->tbl_id = DRV_IOC_MEMID(cmd);
    shm_cmd->io_type = DAL_SHM_IO_OAM;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, shm_cmd->tbl_id);
    shm_cmd->tbl_type = DRV_TBL_TYPE_OAM;
    shm_cmd->index = index;
    shm_cmd->cmd = cmd;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    if (shm_cmd->op == DRV_IOC_WRITE)
    {
        sal_memcpy((uint8*)((uint8*)shm_cmd->data + sizeof(tbl_entry_t)), ((tbl_entry_t *)val)->data_entry, shm_cmd->len);
        sal_memcpy((uint8*)((uint8*)shm_cmd->data + sizeof(tbl_entry_t) + shm_cmd->len), ((tbl_entry_t *)val)->mask_entry, shm_cmd->len);
    }
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    if (shm_cmd->op == DRV_IOC_READ)
    {
       if(DRV_ENTRY_FLAG == DRV_IOC_FIELDID(cmd))
       {
           sal_memcpy(val, shm_cmd->data, shm_cmd->len);
       }
       else
       {
          int32 ret = 0;
          DsEthMep_m dsMep;
          DRV_ENTRY_UNLOCK(lchip);
          ret = p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ](lchip, index, cmd, oper_bmp, (uint32*)&dsMep);
          ret = ret ?ret:drv_get_field(lchip, DRV_IOC_MEMID(cmd), DRV_IOC_FIELDID(cmd), &dsMep, (uint32*)val);
          return ret;
       }
    }
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}

int32
dal_ioctl_mcu_api_shm(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->op = (DRV_IOC_OP(cmd) == DRV_IOC_WRITE) ? DRV_IOC_WRITE : DRV_IOC_READ;
    shm_cmd->tbl_id = index;
    shm_cmd->io_type = DAL_SHM_IO_NORMAL;
    shm_cmd->len = TABLE_ENTRY_SIZE(lchip, DRV_IOC_MEMID(cmd));
    shm_cmd->tbl_type = DRV_TBL_TYPE_MCU;
    shm_cmd->index = cmd;
    shm_cmd->cmd = cmd;
    shm_cmd->oper_bmp = oper_bmp;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    if (shm_cmd->op == DRV_IOC_WRITE)
    {
        sal_memcpy(shm_cmd->data, val, shm_cmd->len);
    }
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    if (shm_cmd->op == DRV_IOC_READ)
    {
        sal_memcpy(val, shm_cmd->data, shm_cmd->len);
    }
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}

uint64
dal_logic_to_phy_shm(uint8 lchip, void* laddr)
{
    return (uint64)(uintptr)laddr;
}

void*
dal_phy_to_logic_shm(uint8 lchip, uint64 paddr)
{
    return (void*)(uintptr)paddr;
}

int32
dal_pci_read_shm(uint8 lchip, uint32 offset, uint32* value)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->op = DRV_IOC_READ;
    shm_cmd->io_type = DAL_SHM_IO_PCI;
    shm_cmd->index = offset;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    sal_memcpy(value, shm_cmd->data, sizeof(uint32));
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}

int32
dal_pci_write_shm(uint8 lchip, uint32 offset, uint32 value)
{
#if defined(TSINGMA_MX) || defined(TSINGMA_GX) || defined(ARCTIC)
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->op = DRV_IOC_WRITE;
    shm_cmd->io_type = DAL_SHM_IO_PCI;
    shm_cmd->index = offset;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    sal_memcpy(shm_cmd->data, &value, sizeof(uint32));
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
#endif
    return 0;
}


int32
dal_pci_read_ext_shm(uint8 lchip, uint64 offset, uint32 len, uint32* p_value)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->op = DRV_IOC_READ;
    shm_cmd->io_type = DAL_SHM_IO_PCI_EXT;
    shm_cmd->index = offset;
    shm_cmd->cmd = 0;
    shm_cmd->len = len;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    sal_memcpy(p_value, shm_cmd->data, len*4);
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}

int32
dal_pci_write_ext_shm(uint8 lchip, uint64 offset, uint32 len, uint32* p_value)
{
    DRV_SHM_WAIT_VAL
    dal_shm_cmd_t* shm_cmd;
    DRV_ENTRY_LOCK(lchip);
    shm_cmd = g_dal_shm_pci_addr[lchip];
    shm_cmd->op = DRV_IOC_WRITE;
    shm_cmd->io_type = DAL_SHM_IO_PCI_EXT;
    shm_cmd->index = offset;
    shm_cmd->cmd = 0;
    shm_cmd->len = len;
    shm_cmd->status = 0;
    shm_cmd->done = 0;
    sal_memcpy(shm_cmd->data, p_value, len*4);
    shm_cmd->valid = 1;
    DRV_SHM_WAIT
    DRV_ENTRY_UNLOCK(lchip);
    return shm_cmd->status;
}

/* alloc dma memory from memory pool*/

STATIC void
_dal_dma_mem_split(dal_shm_dma_mem_t *curr, uint32 size)
{
    dal_shm_dma_mem_t *next;
    size += sizeof(dal_shm_dma_mem_t);
    if (size & 0xF)
    {
        size += (0x10 - (size & 0xF));
    }
    next = (dal_shm_dma_mem_t *)((uint8*)curr + size);
    next->size = curr->size - size;
    next->free = 1;
    next->next = curr->next;
    curr->size = size - sizeof(dal_shm_dma_mem_t);
    curr->free = 0;
    curr->next = next;
}

STATIC void
_dal_dma_mem_merge(dal_shm_dma_mem_t* curr)
{
    while (curr && curr->next)
    {
        if (curr->free && curr->next->free)
        {
            curr->size += (curr->next->size + sizeof(dal_shm_dma_mem_t));
            curr->next = curr->next->next;
        }
        curr = curr->next;
    }
}

STATIC void*
_dal_dma_malloc_shm(uint8 lchip, uint32 size)
{
    dal_shm_dma_mem_t *curr;
    if (!size)
    {
        return NULL;
    }
    SHM_DMA_LOCK();
    curr = g_dal_dma_shm_list[lchip];
    while ((!curr->free || curr->size < size) && (curr->next != NULL))
    {
        curr = curr->next;
    }
    if (!curr->free || curr->size < size)
    {
        SHM_DMA_UNLOCK();
        return NULL;
    }
    if (curr->size == size)
    {
        curr->free = 0;
    }
    else
    {
        _dal_dma_mem_split(curr, size);
    }
    SHM_DMA_UNLOCK();
    return (void*)((uint8*)curr + sizeof(dal_shm_dma_mem_t));
}
STATIC void
_dal_dma_free_shm(uint8 lchip, void* ptr)
{
    dal_shm_dma_mem_t* head;
    dal_shm_dma_mem_t* curr;
    SHM_DMA_LOCK();
    head = g_dal_dma_shm_list[lchip];
    if (ptr >= (void*)head && ptr <= (void*)((uint8*)head + DAL_SHM_DMA_SIZE))
    {
        curr = ((dal_shm_dma_mem_t*)((uint8*)ptr - sizeof(dal_shm_dma_mem_t)));
        curr->free = 1;
        _dal_dma_mem_merge(head);
    }
    SHM_DMA_UNLOCK();
    return;
}

uint32*
dal_dma_alloc_shm(uint8 lchip, int32 size, int32 type)
{
    return _dal_dma_malloc_shm(lchip, size);
}

/*free memory to memory pool*/
void
dal_dma_free_shm(uint8 lchip, void* ptr)
{
    return _dal_dma_free_shm(lchip, ptr);
}


int32
dal_init_sim_io_cb(uint8 lchip)
{
    uint8 cnt = 0;
    sal_file_t local_fp = NULL;

    if (g_dal_work_mode)
    {
        return 0;
    }
    local_fp = sal_fopen(DEFAULT_SHM_FILENAME, "r");
    if (NULL == local_fp)
    {
        return 0;
    }
    sal_fclose(local_fp);
    g_dal_op.pci_read =  dal_pci_read_shm;
    g_dal_op.pci_write =  dal_pci_write_shm;
    g_dal_op.logic_to_phy =  dal_logic_to_phy_shm;
    g_dal_op.phy_to_logic =  dal_phy_to_logic_shm;
    g_dal_op.dma_alloc =  dal_dma_alloc_shm;
    g_dal_op.dma_free =  dal_dma_free_shm;
    g_dal_op.pci_read_ext =  dal_pci_read_ext_shm;
    g_dal_op.pci_write_ext =  dal_pci_write_ext_shm;
    g_dal_op.pci_write_ext2 =  dal_pci_write_ext_shm;

    if (p_drv_master[lchip]->dev_type >= DRV_TSINGMA)
    {
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_READ] = drv_usw_chip_sram_tbl_read_shm;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE] = drv_usw_chip_sram_tbl_write_shm;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read_shm;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE] = drv_usw_chip_dyn_tbl_write_shm;
    }
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_READ] = drv_usw_chip_tcam_tbl_read_shm;
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_WRITE] = drv_usw_chip_tcam_tbl_write_shm;
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_REMOVE] = drv_usw_chip_tcam_tbl_remove_shm;

    for (cnt = 0; cnt < DRV_IOC_MAX; cnt++)
    {
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_OAM][cnt] = dal_ioctl_oam_api_shm;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_MCU][cnt] = dal_ioctl_mcu_api_shm;
    }

    return DRV_E_NONE;
}



#define ______FOR_CMODEL_USE______

typedef int32 (*SHM_CB)(uint8 lchip, dal_shm_cmd_t *cmd);

int32
cmodel_shm_io_normal(uint8 lchip, dal_shm_cmd_t *cmd)
{
    return p_drv_master[lchip]->ioctl_cb[cmd->tbl_type][cmd->op](0, cmd->index, cmd->cmd, cmd->oper_bmp, (uint32*)cmd->data);
}

int32
cmodel_shm_io_tcam(uint8 lchip, dal_shm_cmd_t *cmd)
{
    tbl_entry_t* entry = (tbl_entry_t*)cmd->data;
    entry->data_entry = (uint32*)((uint8*)entry + sizeof(tbl_entry_t));
    entry->mask_entry = (uint32*)((uint8*)entry->data_entry + cmd->len);
    return p_drv_master[lchip]->ioctl_cb[cmd->tbl_type][cmd->op](0, cmd->index, cmd->cmd, cmd->oper_bmp, (uint32*)entry);
}

int32
cmodel_shm_io_oam(uint8 lchip, dal_shm_cmd_t *cmd)
{
    tbl_entry_t* entry = (tbl_entry_t*)cmd->data;
    if (cmd->op == DRV_IOC_WRITE)
    {
        entry->data_entry = (uint32*)((uint8*)entry + sizeof(tbl_entry_t));
        entry->mask_entry = (uint32*)((uint8*)entry->data_entry + cmd->len);
    }
    return p_drv_master[lchip]->ioctl_cb[cmd->tbl_type][cmd->op](0, cmd->index, cmd->cmd, cmd->oper_bmp, (uint32*)cmd->data);
}

extern int32
dal_pci_read(uint8 lchip, uint32 offset, uint32* value);
extern int32
dal_pci_write(uint8 lchip, uint32 offset, uint32 value);
extern int32
dal_pci_read_ext(uint8 lchip, uint64 offset, uint32 len, uint32* p_value);
extern int32
dal_pci_write_ext(uint8 lchip, uint64 offset, uint32 len, uint32* p_value);
int32
cmodel_shm_io_pci(uint8 lchip, dal_shm_cmd_t *cmd)
{
    return (cmd->op == DRV_IOC_READ) ? dal_pci_read(0, cmd->index, (uint32*)cmd->data)
                                       : dal_pci_write(0, cmd->index, *(uint32*)cmd->data);
}

int32
cmodel_shm_io_pci_ext(uint8 lchip, dal_shm_cmd_t *cmd)
{
    return (cmd->op == DRV_IOC_READ) ? dal_pci_read_ext(0, cmd->index, cmd->len, (uint32*)cmd->data)
                                     : dal_pci_write_ext(0, cmd->index, cmd->len, (uint32*)cmd->data);
}

void
cmode_shm_thrd_handler(uint32 thread, void *para)
{
    uint8 lchip_base = 0;
    dal_shm_cmd_t *cmd = (dal_shm_cmd_t*)(g_dal_shm_pci_addr[lchip_base]);
    SHM_CB cmodel_shm_io_cb[DAL_SHM_IO_MAX] = {
        cmodel_shm_io_normal,
        cmodel_shm_io_tcam,
        cmodel_shm_io_pci,
        cmodel_shm_io_pci_ext,
        cmodel_shm_io_oam
    };

    if (!cmd)
    {
        return;
    }
    while( 1 )
    {
        if (0 == cmd->valid)
        {
            sal_udelay(1);
            continue;
        }
        cmd->valid = 0;
        cmd->status = cmodel_shm_io_cb[cmd->io_type](lchip_base, cmd);
        cmd->done = 1;
    }
}


#define ______CMODEL_CLI______

int32
cmodel_cli_shm_process(uint8 lchip, char* func, void * self, void * vty, int32 argc, char** argv)
{
    cmodel_shm_cli_cmd_t *cmd = (cmodel_shm_cli_cmd_t*)(dal_shm_get_cmodel_cli_cmd_ptr(lchip));
    uint32 loop = 0;
    uint32 len = 0;
    uint32* ptr = (uint32*)cmd->args;
    char*  args = (char*)((char**)cmd->args + argc);

    while (cmd->valid && (loop++ < 1000))
    {
        sal_task_sleep(100);
    }
    if (cmd->valid)
    {
        return 1;
    }

    for (loop = 0; loop < argc; loop++)
    {
        len = sal_strlen(argv[loop]) + 1;
        sal_memcpy(args, argv[loop], len);
        ptr[loop] = (uintptr)(args - (char*)cmd->args);
        len = (len % sizeof(char*)) ? (len + sizeof(char*) - len % sizeof(char*)) : len;
        args += len;
        sal_memset(args, 0, len);
    }
    cmd->argc = argc;
    sal_strcpy(cmd->func, func);
    cmd->status = 0;
    cmd->done = 0;
    cmd->valid = 1;
    return 0;
}

int32
dal_shm_cmodel_cli_process(char* func, int32 argc, char** argv)
{
    uint8 _tmp_lchip = 0;

extern uint8 g_ctcs_api_en;
//extern uint8 g_api_lchip;
extern ctc_vty_info_t g_vty_client;
extern uint8 g_lchip_num;
#undef g_api_lchip
#define g_api_lchip     g_vty_client.api_lchip
    if (g_ctcs_api_en) {
        cmodel_cli_shm_process(g_api_lchip, func, NULL, NULL, argc, argv);
    }else{
        do{
            cmodel_cli_shm_process(_tmp_lchip, func, NULL, NULL, argc, argv); \
        }while (++_tmp_lchip < g_lchip_num); \
    }
    return 0;
}

#ifdef CLANG
#pragma clang diagnostic pop
#endif

#endif
